package com.Angaliwa.Whiteboard{
	import com.Angaliwa.DaisyChain;
	import com.Angaliwa.Settings;
	import com.Angaliwa.Toolbox;
	import com.Angaliwa.Whiteboard;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.events.MouseEvent;
	import flash.events.SyncEvent;
	import flash.filters.DropShadowFilter;
	import flash.geom.Matrix;
	import flash.geom.Rectangle;
	
	import mx.containers.Canvas;
	import mx.core.UIComponent;
	import mx.effects.Fade;
	import mx.effects.easing.Quintic;
	
	public class Navigator{
		public var enabled:Boolean=true,
				   settings:Settings = new Settings(this),
				   whiteboard:Whiteboard;
		
		private var blockContainer:Canvas,
					blockSize:Object = {width:500,height:500};
		
		/*
			Available daisyChain actions:
			- startDrag
			- endDrag
			- dragging
		*/
		public var daisyChain:DaisyChain = new DaisyChain(this);
		
		private var nav:Canvas,
					innerNav:Canvas,
					isDragging:Boolean,
					bounds:Rectangle;
		
		public function init():void{
			// Initialize the default settings
			settings.setDefaults({width: 150,
								  alpha: 0.8,
								  innerNavAlpha: 0.6,
								  innerNavStyles:{backgroundColor: 0x333333},
								  title:'Navigator',
								  animateFirst:true,
								  animateFirstDuration: 1000,
								  animateFirstEasing: Quintic.easeOut,
								  animateFirstStartDelay: 1000,
								  showShadow:true,
								  shadowEffect:new DropShadowFilter(0,45,0x000000,0.7,6,6,2)
								 });
			
			if(settings.get('container')){
				nav = new Canvas();
				nav.verticalScrollPolicy="off";
				nav.horizontalScrollPolicy="off";
				nav.alpha = settings.get('alpha');
				
				// Shadow effect
				// TODO: Check out if there's a better way to let the user add
				// filters, allowing them to use more filters than just the
				// shadow.
				if(settings.get('showShadow')){
					var shad:DropShadowFilter = settings.get('shadowEffect');
					nav.filters = [shad];
				}
				
				innerNav = new Canvas();
				innerNav.name = "innerNav";
				innerNav.alpha = settings.get('innerNavAlpha');
				
				// Apply the styles, if any
				Toolbox.applyStyles(nav, settings.get('styles'));
				Toolbox.applyStyles(innerNav, settings.get('innerNavStyles'));
				
				// Add the navigator to the viewport.
				nav.addChild(innerNav);
				settings.get('container').addChild(nav);
				
				// Let the Navigator update while the user is
				// dragging the whiteboard around by using
				// the Whiteboard's Hand module's daisyChain.
				if(whiteboard.features.hasOwnProperty("hand"))
					whiteboard.features.hand.daisyChain.a(['dragging','restorePositionUpdate'], move);
				
				//if(whiteboard.features.hasOwnProperty("sync"))
				//	whiteboard.features.sync.daisyChain.a('syncHandlerTimedTrigger', drawThumb);
				nav.setStyle("backgroundColor", 0xffffff);
				nav.setStyle("backgroundAlpha", 0.7);
				
				// Add event listeners for when the user wants to
				// use the navigator to look around the whiteboard.
				innerNav.addEventListener(MouseEvent.MOUSE_DOWN, startDrag);
				innerNav.addEventListener(MouseEvent.MOUSE_UP, endDrag);
				innerNav.addEventListener(MouseEvent.MOUSE_MOVE, dragging);
				innerNav.addEventListener(MouseEvent.ROLL_OUT, endDrag);
				
				// Run the move() function one time for the
				// initial position/size.
				move();
			}
		}
		
		private function move(e:MouseEvent=undefined):void{
			if(!isDragging){
				var w:int = whiteboard.getContainer().width,
					h:int = whiteboard.getContainer().height,
					r:int = Math.floor(w/settings.get('width')),
					x:int = whiteboard.innerBoard.x,
					y:int = whiteboard.innerBoard.y;
				
				// Resize the navigator to fit the whiteboard
				nav.width = settings.get('width');
				nav.height= Math.floor(h/r);
				
				// Resize the navigator's viewport to fit the
				// current viewport.
				innerNav.width = whiteboard.board.width/r;
				innerNav.height= whiteboard.board.height/r;
				
				innerNav.x = (0-x/r);
				innerNav.y = (0-y/r);
			}
		}
		
		public function drawThumb(e:SyncEvent=undefined):void{
			if(!blockContainer){
				blockContainer = new Canvas();
				blockContainer.x = 0;
				blockContainer.y = 0;
				blockContainer.width = whiteboard.getContainer().width;
				blockContainer.height = whiteboard.getContainer().height;
				
				// TODO: Debug, should me synced with the Whiteboard's 
				// background color later on.
				blockContainer.setStyle("backgroundColor", 0xffffff);
				
				nav.addChildAt(blockContainer,0);
				
				// Animation
				if(settings.get('animateFirst')){
					blockContainer.alpha=0;
					var ani:Fade = new Fade(blockContainer);
					ani.duration = settings.get('animateFirstDuration');
					ani.easingFunction = settings.get('animateFirstEasing');
					ani.alphaFrom = 0;
					ani.alphaTo = 1;
					ani.startDelay = settings.get('animateFirstStartDelay');
					ani.play();
				}
			}
			
			// Debug info.
			var tDate:Date = new Date();
			var iTime:Number = tDate.time;
			
			var verBlocks:int = Math.ceil(whiteboard.getContainer().width/blockSize.width);
			var horBlocks:int = Math.ceil(whiteboard.getContainer().height/blockSize.height);
			
			for(var i:int=0; i < horBlocks; i++){
				for(var j:int=0; j < verBlocks; j++){
					var rect:Rectangle = new Rectangle(0,0,blockSize.width, blockSize.height);
					var matr:Matrix = new Matrix(1,0,0,1,-(blockSize.width*i),-(blockSize.height*j));
					
					var blckData:BitmapData = new BitmapData(blockSize.width, blockSize.height);
					blckData.draw(whiteboard.getContainer(), matr, null, null, rect);
					
					if(!blockContainer.getChildByName("sub_"+i+"_"+j)){
						var nwBlock:UIComponent = new UIComponent();
						nwBlock.name = "sub_"+i+"_"+j;
						nwBlock.x = blockSize.width*i;
						nwBlock.y = blockSize.height*j;
						
						nwBlock.addChild(new Bitmap());
						blockContainer.addChild(nwBlock);
					}
					
					((blockContainer.getChildByName("sub_"+i+"_"+j) as UIComponent).getChildAt(0) as Bitmap).bitmapData = blckData;
				}
			}
			
			var toPx:Number = (100/whiteboard.getContainer().width)*nav.width,
				toPy:Number = (100/whiteboard.getContainer().height)*nav.height;
			
			blockContainer.x = 0;
			blockContainer.y = 0;
			blockContainer.scaleX = (toPx/100);
			blockContainer.scaleY = (toPy/100);
			
			// Debug info.
			var aDate:Date = new Date();
			var iByteArrTime:Number = aDate.time;
			trace('NAVIGATOR: Generated thumbnail in ' + (iByteArrTime-iTime) + ' milliseconds');
		}
		
		public function startDrag(e:MouseEvent):void{
			if(whiteboard.features.hasOwnProperty("hand"))
				whiteboard.features.hand.stopRestorePosition();
			
			bounds = new Rectangle(0,0,
							nav.width-innerNav.width,
							nav.height-innerNav.height);
			
			innerNav.startDrag(false,bounds);
			
			daisyChain.run('startDrag', e);
			isDragging=true;
		}
		
		private function dragging(e:MouseEvent):void{
			var r:int = Math.floor(whiteboard.getContainer().width/settings.get('width'));
			
			whiteboard.innerBoard.x = 0-innerNav.x*r;
			whiteboard.innerBoard.y = 0-innerNav.y*r;
			
			daisyChain.run('dragging', e);
		}
		
		public function endDrag(e:MouseEvent):void{
			innerNav.stopDrag();
			isDragging=false;
			
			daisyChain.run('endDrag', e);
		}
	}
}